﻿using System;
using Gumini.JulaDB.DataTypes;

namespace Gumini.JulaDB.Expressions
{
    /// <summary>
    /// Represents an expression result which consist of the type and value pair.
    /// May also represent null, which has no type.
    /// </summary>
    public class TypedValue
    {
        private enum ValueMode
        {
            Standard,
            Null,
            Asterisk
        }

        private readonly ValueMode _mode;
        private static readonly TypedValue _asterisk = new TypedValue(null, null, ValueMode.Asterisk);
        private static readonly TypedValue _null = new TypedValue(null, null, ValueMode.Null);

        public TypedValue(DataType type, object value)
        {
            this.Type = type;
            this.Value = value;
            _mode = (value == null) ? ValueMode.Null : ValueMode.Standard;
        }

        private TypedValue(DataType type, object value, ValueMode mode)
        {
            this.Type = type;
            this.Value = value;
            _mode = mode;
        }

        public static TypedValue Null
        {
            // null has no value
            get { return _null; }
        }
        
        public static TypedValue Asterisk
        {
            get { return _asterisk; }
        }

        public bool IsNull
        {
            get { return _mode == ValueMode.Null; }
        }

        public bool IsAsterisk
        {
            get { return _mode == ValueMode.Asterisk; }
        }

        public DataType Type { get; private set; }

        public object Value { get; private set; }

        public override string ToString()
        {
            if (this.IsNull)
                return "null";
            if (this.IsAsterisk)
                return "asterisk";
            return String.Format("{0}:{1}", this.Type, this.Value);
        }

        public override int GetHashCode()
        {
            if (_mode != ValueMode.Standard)
                return 1;
            else
                return Value.GetHashCode();
        }

        public override bool Equals(object obj)
        {
            var other = obj as TypedValue;
            if (obj == null)
                return false;
            return Object.Equals(this.Value, other.Value);
        }
    }
}
